#include "StdAfx.h"
#include "afxsock.h"

#include ".\upload.h"

ECMUpload::ECMUpload(void)
{
	going_to_shutdown = FALSE;
	preader = NULL;
	InitializeCriticalSection(&CS);
	Idx = 0;
}

ECMUpload::~ECMUpload(void)
{
	DeleteCriticalSection(&CS);
}

static void
URLencode(LPCTSTR str, CString &Str)
{
	char	*encstr, buf[2+1];
	unsigned char c;
	int i, j;

	if (str == NULL)
		return;
	encstr = (char *)LocalAlloc(0, strlen(str) * 3 + 1);
	for (i = j = 0; str[i]; i++) {
		c = (unsigned char)str[i];
		if ((c >= '0') && (c <= '9'))
			encstr[j++] = c;
		else if ((c >= 'A') && (c <= 'Z'))
			encstr[j++] = c;
		else if ((c >= 'a') && (c <= 'z'))
			encstr[j++] = c;
		else if ((c == '@') || (c == '.') ||
			 (c == '/') || (c == '\\') ||
			 (c == '-') || (c == '_') || (c == ':'))
			encstr[j++] = c;
		else {
			sprintf(buf, "%02x", c);
			encstr[j++] = buf[0];
			encstr[j++] = buf[1];
		}
	}
	encstr[j] = '\0';
	Str = encstr;
	LocalFree(encstr);
}

BOOL
ECMUpload::Upload(CFile *sf)
{
	CArchive	writer(sf, CArchive::store);
	CString		Str, URLFile;
	ULONGLONG	TotalLen = pfile->GetLength();
	ULONGLONG	CurrLen = 0;
	int		PrevProg = 0, Prog;

	TRY {
		URLencode(pfile->GetFileName(), URLFile);
		Str.Format("GET /upload?upfile=%s&DOM=%s HTTP/1.0\n", URLFile, DOM);
		writer.WriteString(Str);
		writer.WriteString("Content-type: upload\n");
		Str.Format("Content-Length: %u\n", TotalLen);
		writer.WriteString(Str);
		Str.Format("Cookie: %s\n\n", Cookie);
		writer.WriteString(Str);

		char	buf[4096];
		int	nread;

		while ((nread = pfile->Read(buf, 4096)) > 0) {
			if (going_to_shutdown)
				return FALSE;
			writer.Write(buf, nread);
			CurrLen += nread;
			Prog = (int)((1.0 * CurrLen / TotalLen) * 100);
			if (PrevProg < Prog) {
				preport->SetProgress(Prog);
				PrevProg = Prog;
			}
		}
	}
	CATCH_ALL(pEx) {
		writer.Abort();
		return FALSE;
	}
	END_CATCH_ALL
	writer.Flush();
	writer.Close();
	return TRUE;
}

BOOL
ECMUpload::GetResponse(CFile *sf)
{
	CString	Str;
	BOOL	res = FALSE;
	CArchive	reader(sf, CArchive::load);

	preader = &reader;
	while (reader.ReadString(Str)) {
		if (Str.IsEmpty()) {
			CString	result;
			if (reader.ReadString(result)) {
				if (sscanf(result.GetBuffer(), "%u", &Idx) == 1 && Idx > 0)
					res = TRUE;
				break;
			}
		}
	}
	EnterCriticalSection(&CS);
	reader.Close();
	preader = NULL;
	LeaveCriticalSection(&CS);
	return res;
}

void
ECMUpload::Cancel(void)
{
	going_to_shutdown = TRUE;
	EnterCriticalSection(&CS);
	if (preader)
		preader->Abort();
	LeaveCriticalSection(&CS);
}

static UINT
Worker(LPVOID pParam)
{
	ECMUpload	*upload = (ECMUpload *)pParam;

	AfxSocketInit();

	CSocket	sock;
	if (!sock.Create() || !sock.Connect(upload->ServerName, upload->port)) {
		upload->preport->Done(FALSE);
		return 1;
	}

	CSocketFile	sf(&sock);

	TRY {
		if (!upload->Upload(&sf) || !upload->GetResponse(&sf)) {
			upload->preport->Done(FALSE);
			return 1;
		}
	}
	CATCH_ALL(pEx) {
		upload->preport->Done(FALSE);
		return 1;
	}
	END_CATCH_ALL
	upload->preport->Done(TRUE);
	return 0;
}

void
ECMUpload::Run(CReport *preport, CFile *pfile, LPCTSTR ServerName, unsigned short port, LPCTSTR DOM, LPCTSTR Cookie)
{
	this->preport = preport;
	this->pfile = pfile;
	this->ServerName = ServerName;
	this->port = port;
	this->DOM = DOM;
	this->Cookie = Cookie;

	CWinThread	*worker;

	worker = AfxBeginThread(Worker, this, 0, 0, CREATE_SUSPENDED, NULL);
	worker->m_bAutoDelete = TRUE;
	worker->ResumeThread();
}
